package com.mtw.bbs.article.controller.open;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mtw.bbs.article.pojo.elasticsearch.ArticleESIndex;
import com.mtw.bbs.article.pojo.entity.ArticleIndex;
import com.mtw.bbs.article.pojo.vo.ArticleVo;
import com.mtw.bbs.article.pojo.vo.TopicVo;
import com.mtw.bbs.article.service.ArticleIndexService;
import com.mtw.bbs.article.service.TopicIndexService;
import com.mtw.bbs.util.ArticleComponent;
import com.mtw.bbs.util.ArticleUtils;
import com.mtw.bbs.util.ESUtils;
import com.mtw.bbs.common.core.constant.ServiceConstant;
import com.mtw.bbs.common.core.constant.SysConstant;
import com.mtw.bbs.common.core.enums.SortEnum;
import com.mtw.bbs.common.core.security.UserDetails;
import com.mtw.bbs.common.core.security.context.SecurityContextHolder;
import com.mtw.bbs.common.core.util.BeanCopyUtils;
import com.mtw.bbs.common.core.vo.Result;
import com.mtw.bbs.common.web.annotation.AccessLimit;
import com.mtw.bbs.article.pojo.vo.LikeCountVo;
import com.mtw.bbs.userAdmin.feign.UserClient;
import com.mtw.bbs.userAdmin.pojo.dto.UserDto;
import com.mtw.bbs.userAdmin.pojo.vo.UserInfoVo;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.client.elc.NativeQueryBuilder;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * 开发文章接口层
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("open/article")
public class OpenArticleController {

    private static final Logger log = LoggerFactory.getLogger(OpenArticleController.class);
    private final UserClient userClient;
    private final ArticleComponent articleComponent;
    private final ThreadPoolTaskExecutor bizExecutor;
    private final TopicIndexService topicIndexService;
    private final ArticleIndexService articleIndexService;
    private final ElasticsearchTemplate elasticsearchTemplate;


    /**
     * 文章分页查询文章
     *
     * @param page        当前页
     * @param size        分页大小
     * @param contentType 内容类型，图文还是视频
     */
//    @AccessLimit(second = 30,maxTime = 20)
    @GetMapping("/index")
    public Result getIndexArticle(@RequestParam(name = "page") int page,
                                  @RequestParam(name = "size") int size,
                                  @RequestParam(name = "contentType", required = false) Integer contentType) {


        LambdaQueryWrapper<ArticleIndex> lqw = new LambdaQueryWrapper<>();
        lqw.eq(ArticleIndex::getStatus, ServiceConstant.STATUS_ENABLE);
        lqw.eq(ArticleIndex::getApproveStatus, SysConstant.DEFAULT_ENABLE);
        lqw.eq(contentType != null, ArticleIndex::getContentType, contentType);
        lqw.orderByDesc(ArticleIndex::getLevel);
        // TODO
        lqw.orderByDesc(ArticleIndex::getCreatedDate);

        Page<ArticleVo> voPage = articleIndexService.getArticlePage(page, size, lqw);

        return Result.success(voPage);
    }




    /**
     * 话题文章分页查询文章
     *
     * @param page        当前页
     * @param size        分页大小
     * @param topicId     话题id
     * @param order       排序方式
     */
//    @AccessLimit(second = 30,maxTime = 20)
    @GetMapping("/topic")
    public Result getTopicArticle(@RequestParam(name = "page") int page,
                                  @RequestParam(name = "size") int size,
                                  @RequestParam(name = "topic") String topicId,
                                  @RequestParam(name = "order", required = false) Integer order) {


        LambdaQueryWrapper<ArticleIndex> lqw = new LambdaQueryWrapper<>();
        lqw.eq(ArticleIndex::getStatus, ServiceConstant.STATUS_ENABLE);
        lqw.eq(ArticleIndex::getApproveStatus, SysConstant.DEFAULT_ENABLE);
        lqw.eq( ArticleIndex::getTopicId, topicId);


        if (SortEnum.SORT_TIME.getCode().equals(order)) {
            lqw.orderByDesc(ArticleIndex::getCreatedDate);
        } else {
            lqw.orderByDesc(ArticleIndex::getLevel);
        }

        Page<ArticleVo> voPage = articleIndexService.getArticlePage(page, size, lqw);

        return Result.success(voPage);
    }


    /**
     * 搜索文章
     *
     * @param page 当前页
     * @param size 分页大小
     * @param keyword  关键词
     */
    @GetMapping("/search")
    public Result searchData(@RequestParam(name = "page") int page,
                             @RequestParam(name = "size") int size,
                             @RequestParam(name = "keyword") String keyword) {

        if (StringUtils.isBlank(keyword)) {
            return Result.fail("请输入关键词");
        }

        //高亮查询
        HighlightQuery highlightQuery = ESUtils.getHighlightQuery(ArticleESIndex.class, "content");
        // 查询构建
        NativeQueryBuilder builder = new NativeQueryBuilder();
        builder.withHighlightQuery(highlightQuery);
        builder.withQuery(q -> q.match(m -> m.field("content").query(keyword)));
        builder.withFilter(q -> q.bool(
                b -> b.must(m -> m.term(t -> t.field("status").value(SysConstant.DEFAULT_ENABLE)))
                        .must(m -> m.term(t -> t.field("approveStatus").value(SysConstant.DEFAULT_ENABLE)))));
        builder.withPageable(PageRequest.of(page - 1, size));
        builder.withSort(Sort.by(Sort.Direction.DESC, "createdDate"));

        // es搜索结果
        SearchHits<ArticleESIndex> search = elasticsearchTemplate.search(builder.build(), ArticleESIndex.class);
        // 无命中的数据
        if (!search.hasSearchHits()) {
            return Result.success(new Page<>(page, size, 0));
        }

        Page<ArticleVo> voPage = new Page<>(page, size, search.getTotalHits());
        // 设置结果
        setSearchResultData(search,voPage);
        return Result.success(voPage);
    }



    /**
     * 话题文章分页查询文章
     *
     * @param page    当前页
     * @param size    分页大小
     * @param topicId 话题id
     * @param keyword     关键词
     */
    @GetMapping("/search/topic")
    public Result searchByTopic(@RequestParam(name = "page") int page,
                                @RequestParam(name = "size") int size,
                                @RequestParam(name = "topic") String topicId,
                                @RequestParam(name = "keyword", required = false) String keyword,
                                @RequestParam(name = "order", required = false) String order) {


        if (StringUtils.isBlank(keyword) || StringUtils.isBlank(topicId)) {
            return Result.fail("请输入关键词");
        }

        //高亮查询
        HighlightQuery highlightQuery = ESUtils.getHighlightQuery(ArticleESIndex.class, "content");
        // 查询构建
        NativeQueryBuilder builder = new NativeQueryBuilder();
        builder.withHighlightQuery(highlightQuery);
        builder.withQuery(q -> q.match(m -> m.field("content").query(keyword)));
        builder.withFilter(q -> q.bool(
                    b -> b.must(m -> m.term(t -> t.field("topicId").value(topicId)))
                         .must(m -> m.term(t -> t.field("status").value(SysConstant.DEFAULT_ENABLE)))
                         .must(m -> m.term(t -> t.field("approveStatus").value(SysConstant.DEFAULT_ENABLE)))));
        builder.withPageable(PageRequest.of(page - 1, size));
        builder.withSort(Sort.by(Sort.Direction.DESC, "createdDate"));

        // es搜索结果
        SearchHits<ArticleESIndex> search = elasticsearchTemplate.search(builder.build(), ArticleESIndex.class);
        // 无命中的数据
        if (!search.hasSearchHits()) {
            return Result.success(new Page<>(page, size, 0));
        }

        Page<ArticleVo> voPage = new Page<>(page, size, search.getTotalHits());
        setSearchResultData(search,voPage);
        return Result.success(voPage);
    }


    /**
     * 根据用户名分页查询发布的文章
     *
     * @param username 用户名
     * @param page     当前页
     * @param size     分页大小
     * @param key      关键词
     */
    @GetMapping("/user/{username}")
    public Result getArticlePageByUser(@PathVariable("username") String username,
                                       @RequestParam(name = "page") int page,
                                       @RequestParam(name = "size") int size,
                                       @RequestParam(name = "sort", required = false) Integer sort,
                                       @RequestParam(name = "key", required = false) String key) {

        Result<UserDto> userinfo = userClient.getUserInfoByUsername(username);
        if (userinfo.isFail() || userinfo.getData() == null) {
            return Result.fail("用户不存在");
        }

        // 搜索
        if (StringUtils.isNotBlank(key)) {
            //高亮查询
            HighlightQuery highlightQuery = ESUtils.getHighlightQuery(ArticleESIndex.class, "content");
            // 查询构建
            NativeQueryBuilder builder = new NativeQueryBuilder();
            builder.withHighlightQuery(highlightQuery);
            builder.withQuery(q -> q.match(m -> m.field("content").query(key)));
            builder.withFilter(f -> f.term(m -> m.field("createdBy").value(userinfo.getData().getId())));
            builder.withFilter(q -> q.bool(b -> b.must(m -> m.term(t -> t.field("status").value(SysConstant.DEFAULT_ENABLE)))));
            builder.withFilter(q -> q.bool(b -> b.must(m -> m.term(t -> t.field("approveStatus").value(SysConstant.DEFAULT_ENABLE)))));
            // 分页
            builder.withPageable(PageRequest.of(page - 1, size));
            builder.withSort(Sort.by(Sort.Direction.DESC, "createdDate"));
            // es搜索结果
            SearchHits<ArticleESIndex> search = elasticsearchTemplate.search(builder.build(), ArticleESIndex.class);
            // 无命中的数据
            if (!search.hasSearchHits()) {
                return Result.success(new Page<>(page, size, 0));
            }

            Page<ArticleVo> voPage = new Page<>(page, size, search.getTotalHits());
            setSearchResultData(search,voPage);
            return Result.success(voPage);
        }

        // 普通查询
        LambdaQueryWrapper<ArticleIndex> lqw = new LambdaQueryWrapper<>();
        lqw.eq(ArticleIndex::getStatus, ServiceConstant.STATUS_ENABLE);
        lqw.eq(ArticleIndex::getApproveStatus, SysConstant.DEFAULT_ENABLE);
        lqw.eq( ArticleIndex::getCreatedBy, userinfo.getData().getId());

        if (SortEnum.SORT_LIKE.getCode().equals(sort)) {
//            qw.orderByDesc("ai.like_count");
        } else {
            lqw.orderByDesc(ArticleIndex::getCreatedDate);
        }

        Page<ArticleVo> voPage = articleIndexService.getArticlePage(page, size, lqw);
        return Result.success(voPage);
    }


    /**
     * 获取文章信息
     *
     * @param id 文章主键id
     * @return 文章VO
     */
    @GetMapping("/info/{id}")
    public Result getInfo(@PathVariable("id") String id) {

        ArticleVo vo = articleIndexService.getInfoById(id);
        if (vo != null) {

            // 设置评论总数
            CompletableFuture<Boolean> replyF = CompletableFuture.supplyAsync(() -> {
                Integer replyCount = articleComponent.getArticleReplyCount(id);
                vo.setReplyCount(replyCount);
                return true;
            }, bizExecutor);


            // 点赞信息
            LikeCountVo liked = articleComponent.getArticleLikeInfo(id);
            if (liked != null){
                vo.setLikeOrDis(liked.getLikeStatus());
                vo.setLikeCount(liked.getCount());
            }

            try {
                replyF.get(8, TimeUnit.SECONDS);
            }catch (Exception e){
                log.error("异步获取子评论出错。",e);
            }

            return Result.success(vo);
        }



        return Result.fail("文章不存在");
    }


    /**
     * 设置搜索结果数据
     * @param result    es查询结果
     * @param voPage    结果
     */
    public void setSearchResultData(SearchHits<ArticleESIndex> result, Page<ArticleVo> voPage) {

        // 当前用户
        UserDetails user = SecurityContextHolder.getContext().getAuthentication();
        // 发帖人id
        List<String> uidList = result.getSearchHits().stream().map(x->x.getContent().getCreatedBy()).toList();
        // 获取发帖人信息
        Map<String, UserInfoVo> posterVoMap = ArticleUtils.getUserInfoVoMap2R(userClient.getUserInfoByIds(uidList.toArray(String[]::new)));

        List<ArticleVo> voList = result.getSearchHits().stream().map(x -> {
            ArticleVo vo = BeanCopyUtils.copyBean(x.getContent(), ArticleVo.class);
            // 发帖人信息
            vo.setPoster(posterVoMap.get(x.getContent().getCreatedBy()));
            // 回写高亮字段
            vo.setContent(x.getHighlightFields().get("content").get(0));
            // 话题信息
            TopicVo topicInfo = topicIndexService.getTopicInfo(x.getContent().getTopicId());
            vo.setTopicInfo(topicInfo);
            return vo;
        }).toList();

        articleComponent.setArticleSubject(voList,user == null?null:user.getId());
        voPage.setRecords(voList);
    }


}
